package com.gugee.tiktok.web.service;


import cn.hutool.core.date.DateUtil;
import com.gugee.common.web.util.ESUtil;
import com.gugee.common.web.system.promise.repository.PermissionLimitRepository;
import com.gugee.common.web.system.promise.repository.PermissionRecordRepository;
import com.gugee.common.web.system.promise.repository.PermissionRepository;
import com.gugee.tiktok.web.dto.*;
import com.gugee.tiktok.web.repository.*;
import com.gugee.tiktok.web.model.mysql.Blogger;
import com.gugee.tiktok.web.model.mysql.Comparison;
import com.gugee.tiktok.web.model.mysql.ComparisonHistory;
import com.gugee.tiktok.web.model.mysql.ComparisonHistoryDetail;
import com.xiguaji.boot.toolkit.JsonUtil;
import com.xiguaji.boot.toolkit.jdbc.Page;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Service
@Slf4j
public class ComparisonService {

    @Autowired
    RestHighLevelClient client;

    @Autowired
    ComparisonRepository comparisonRepository;

    @Autowired
    ComparisonHistoryRepository comparisonHistoryRepository;

    @Autowired
    ComparisonHistoryDetailRepository comparisonHistoryDetailRepository;

    @Autowired
    BloggerRepository bloggerRepository;

    @Autowired
    BloggerRecordRepository bloggerRecordRepository;

    @Autowired
    AwemeRepository awemeRepository;

    @Autowired
    PermissionRecordRepository permissionRecordRepository;

    @Autowired
    PermissionLimitRepository permissionLimitRepository;

    @Autowired
    PermissionRepository permissionRepository;

    public List<BloggerResponse> getSearchList(String keyword, long userId){
        List<BloggerResponse> bloggerResponses = new ArrayList<>();
        SearchRequest searchRequest = new SearchRequest(ESUtil.BLOGGER_INDEX);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        if(!StringUtils.isEmpty(keyword)){
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            boolQueryBuilder.should(QueryBuilders.matchQuery("uniqueId",keyword));
            boolQueryBuilder.should(QueryBuilders.matchQuery("nickName",keyword));
            boolQueryBuilder.should(QueryBuilders.wildcardQuery("nickName","*"+keyword+"*"));
            boolQueryBuilder.should(QueryBuilders.wildcardQuery("uniqueId","*"+keyword+"*"));
            boolQueryBuilder.minimumShouldMatch(1);
            searchSourceBuilder.query(boolQueryBuilder);
            searchSourceBuilder.size(10);
        }else {
            searchSourceBuilder.size(5);
        }
        searchSourceBuilder.sort("score", SortOrder.DESC);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = null;

        try {
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        val hits = searchResponse.getHits().getHits();

        for (SearchHit hit : hits) {
            SearchDataResponse bloggerResponse = new SearchDataResponse();
            val map = JsonUtil.jsonParse(Map.class,hit.getSourceAsString());

            if((map.get("avatar168").toString().indexOf("sign-sg") > 0 && map.get("avatar168").toString().indexOf("sign-sg") < 30) || (map.get("avatar168").toString().indexOf("sign-va") > 0 && map.get("avatar168").toString().indexOf("sign-va") < 30)){
                bloggerResponse.setAvatar(map.get("avatar168").toString().replace("sign-sg", "amd-va").replace("sign-va", "amd-va").replace("webp", "jpeg"));
            }
            bloggerResponse.setNickname(map.get("nickName").toString());
            bloggerResponse.setUniqueId(map.get("uniqueId").toString());
            bloggerResponse.setFollowerCount(Integer.parseInt(map.get("followerCount").toString()));
            bloggerResponse.setEnterpriseVerifyReason(map.get("enterpriseVerifyReason") == null?"":map.get("enterpriseVerifyReason").toString());
            bloggerResponse.setCustomVerify(map.get("customVerify") == null?"":map.get("customVerify").toString());
            bloggerResponse.setUid(Long.parseLong(map.get("uid").toString()));
            bloggerResponse.setRegion(map.get("region").toString());
            val comparisonOptional = comparisonRepository.findByUserIdAndUid(userId,Long.parseLong(map.get("uid").toString()));

            if(comparisonOptional.isPresent()){
                bloggerResponse.setAdded(true);
            }
            bloggerResponses.add(bloggerResponse);
        }
        return bloggerResponses;
    }

    public List<BloggerResponse> getComparisonBloggerListByUserId(long userId){
        return comparisonRepository.findByUserId(userId);
    }

    public void addComparison(long userId,long uid){
        val comparisonOptional = comparisonRepository.findByUserIdAndUid(userId, uid);

        if(!comparisonOptional.isPresent()){
            Comparison comparison = new Comparison();
            comparison.setUid(uid);
            comparison.setUserId(userId);
            comparison.setCreateTime(System.currentTimeMillis()/1000);
            comparison.setUpdateTime(System.currentTimeMillis()/1000);
            comparison.setCreateBy("add comparison");
            comparison.setUpdateBy("add comparison");
            comparisonRepository.save(comparison);
        }
    }

    public int countComparison(long userId){
        return comparisonRepository.countByUserId(userId);
    }

    public void removeComparison(long userId,long uid){
        val comparisonOptional = comparisonRepository.findByUserIdAndUid(userId, uid);

        if(comparisonOptional.isPresent()){
            comparisonRepository.delete(comparisonOptional.get());
        }
    }

    public Page<HistoryResponse> comparisonHistoryList(int page, int pageSize, long userId){
        val pageData = comparisonHistoryRepository.getPage(page, pageSize, userId);
        pageData.getList().forEach( historyResponse -> historyResponse.setBloggerResponses(comparisonHistoryDetailRepository.getSimpleDataByComparisonHistoryId(historyResponse.getId())));
        return pageData;
    }

    public HistoryDetailResponse getComparisonHistoryData(long comparisonHistoryId){
        HistoryDetailResponse historyDetailResponse = new HistoryDetailResponse();
        Optional<ComparisonHistory> comparisonHistoryOptional = comparisonHistoryRepository.findById(comparisonHistoryId);

        if(comparisonHistoryOptional.isPresent()){
            historyDetailResponse.setCreateTime(comparisonHistoryOptional.get().getCreateTime());
            historyDetailResponse.setId(comparisonHistoryOptional.get().getId());
            historyDetailResponse.setComparisonHistoryDetails(comparisonHistoryDetailRepository.findByComparisonHistoryIdOrderBySortAsc(comparisonHistoryId));
            historyDetailResponse.getComparisonHistoryDetails().forEach( comparisonHistoryDetail -> {
                if((comparisonHistoryDetail.getAvatar().indexOf("sign-sg") > 0 && comparisonHistoryDetail.getAvatar().indexOf("sign-sg") < 30) || (comparisonHistoryDetail.getAvatar().indexOf("sign-va") > 0 && comparisonHistoryDetail.getAvatar().indexOf("sign-va") < 30)){
                    comparisonHistoryDetail.setAvatar(comparisonHistoryDetail.getAvatar().replace("sign-sg", "amd-va").replace("sign-va", "amd-va").replace("webp", "jpeg"));
                }
            });

        }
        return historyDetailResponse;
    }

    public void removeComparisonHistory(long comparisonHistoryId){
        comparisonHistoryRepository.deleteById(comparisonHistoryId);
        comparisonHistoryDetailRepository.deleteByComparisonHistoryId(comparisonHistoryId);
    }

    public int generalHistoryDetail(Long comparisonHistoryId,long userId){
        List<BloggerResponse> bloggerResponses;
        if(null != comparisonHistoryId){
            bloggerResponses = comparisonHistoryDetailRepository.getSimpleDataByComparisonHistoryId(comparisonHistoryId);
        }else {
            bloggerResponses = comparisonRepository.findByUserId(userId);
        }
        ComparisonHistory comparisonHistory = addComparisonHistory(userId);
        generalHistoryDetail(bloggerResponses, comparisonHistory.getId(),userId);
        return comparisonHistory.getId();
    }

    public Map<String,Integer> getComparisonCount(long userId,long roleId){
        long permissionId = permissionRepository.findByName("Comparison").getId();
        val permissionLimitOptional = permissionLimitRepository.findByPermissionIdAndProductId(permissionId, roleId);
        int startDate = Integer.parseInt(DateUtil.format(DateUtil.beginOfMonth(Calendar.getInstance()).getTime(),"yyyyMMdd"));
        int endDate = Integer.parseInt(DateUtil.format(DateUtil.endOfMonth(Calendar.getInstance()).getTime(),"yyyyMMdd"));
        int totalCount = permissionLimitOptional.get().getLimitCount();
        int recordCount = permissionRecordRepository.countByPermissionLimitIdAndUserIdAndBelongBetween(permissionLimitOptional.get().getId(),userId,startDate,endDate);

        Map<String,Integer> result = new HashMap<>();
        result.put("remaining",totalCount - recordCount);
        result.put("consumed",recordCount);
        return result;
    }

    public ComparisonHistory getNewComparisonHistory(long userId){
        return comparisonHistoryRepository.findByUserId(userId);
    }

    public ComparisonHistory addComparisonHistory(long userId){
        ComparisonHistory comparisonHistory = new ComparisonHistory();
        comparisonHistory.setUserId(userId);
        comparisonHistory.setCreateBy("add ComparisonHistory");
        comparisonHistory.setUpdateBy("add ComparisonHistory");
        comparisonHistory.setCreateTime(System.currentTimeMillis()/1000);
        comparisonHistory.setUpdateTime(System.currentTimeMillis()/1000);
        return comparisonHistoryRepository.save(comparisonHistory);
    }

    public void generalHistoryDetail(List<BloggerResponse> bloggerResponses,long comparisonHistoryId,long userId){
        for (int i = 0; i < bloggerResponses.size(); i++) {
            ComparisonHistoryDetail comparisonHistoryDetail = setHistoryDetail(bloggerResponses.get(i));
            comparisonHistoryDetail.setComparisonHistoryId(comparisonHistoryId);
            comparisonHistoryDetail.setUserId(userId);
            comparisonHistoryDetail.setSort((long)i);
            comparisonHistoryDetailRepository.save(comparisonHistoryDetail);
        }
    }

    private ComparisonHistoryDetail setHistoryDetail(BloggerResponse bloggerResponse){
        Blogger blogger = bloggerRepository.findByOUid(bloggerResponse.getUid()).get();
        ComparisonHistoryDetail comparisonHistoryDetail = new ComparisonHistoryDetail();
        comparisonHistoryDetail.setAvatar(blogger.getOAvatar168());
        comparisonHistoryDetail.setAvgLikes(blogger.getOAvgLikes());
        comparisonHistoryDetail.setAvgReviews(blogger.getOAvgReviews());
        comparisonHistoryDetail.setAvgShare(blogger.getOAvgShare());
        comparisonHistoryDetail.setAvgViews(blogger.getOAvgViews());

        BigDecimal dscCount = new BigDecimal( blogger.getOAvgLikes()+blogger.getOAvgShare()+blogger.getOAvgReviews());
        BigDecimal playCount = new BigDecimal(blogger.getOAvgViews());
        try{
            comparisonHistoryDetail.setEngagementRate(dscCount.divide(playCount,3, RoundingMode.FLOOR).multiply(new BigDecimal(100)).setScale(1).doubleValue());
        }catch (Exception e){
            log.error("计算参与率出错",e);
            comparisonHistoryDetail.setEngagementRate(0.0);
        }
        comparisonHistoryDetail.setAwemeCount((long)blogger.getOAwemeCount());
        comparisonHistoryDetail.setBloggerType(blogger.getBloggerType());
        comparisonHistoryDetail.setBioUrl(blogger.getBioUrl());
        comparisonHistoryDetail.setCustomVerify(blogger.getCustomVerify());
        comparisonHistoryDetail.setFollowerCount((long)blogger.getOFollowerCount());
        comparisonHistoryDetail.setLikesCount(blogger.getOTotalFavorited());
        comparisonHistoryDetail.setBioUrl(blogger.getBioUrl());
        comparisonHistoryDetail.setInsId(blogger.getInsId());
        comparisonHistoryDetail.setYoutubeChannelId(blogger.getYoutubeChannelId());
        comparisonHistoryDetail.setWithFusionShopEntry(blogger.getWithFusionShopEntry());
        comparisonHistoryDetail.setUid(blogger.getOUid());
        comparisonHistoryDetail.setTwitterId(blogger.getTwitterId());
        comparisonHistoryDetail.setEnterpriseVerifyReason(blogger.getEnterpriseVerifyReason());
        comparisonHistoryDetail.setRegion(blogger.getORegion());
        comparisonHistoryDetail.setNickname(blogger.getONickname());
        comparisonHistoryDetail.setScore(blogger.getScore());
        long startTime = getStartDay();
        long endTime = getEndDay(startTime,6);
        BloggerGrowth bloggerGrowth = getWeekGrowth(blogger.getOUid(),endTime,startTime);
        comparisonHistoryDetail.setWeekFollowerCount(bloggerGrowth.getFollowerGrowth());
        comparisonHistoryDetail.setWeekLikes(bloggerGrowth.getLikeGrowth());
        comparisonHistoryDetail.setWeekReviews(bloggerGrowth.getReviewGrowth());
        comparisonHistoryDetail.setWeekShare(bloggerGrowth.getShareGrowth());
        comparisonHistoryDetail.setWeekViews(bloggerGrowth.getViewGrowth());
        int newposts = awemeRepository.countByOUidAndOCreateTimeBetween(blogger.getOUid(),
                endTime,
                startTime);
        comparisonHistoryDetail.setWeekAwemeCount((long)newposts);
        comparisonHistoryDetail.setUniqueId(blogger.getOUniqueId());
        comparisonHistoryDetail.setCreateBy("add");
        comparisonHistoryDetail.setUpdateBy("add");
        return comparisonHistoryDetail;
    }

    private BloggerGrowth getWeekGrowth(long uid,long startTime,long endTime){
        return bloggerRecordRepository.findByGroupData(uid, getDayCode(startTime), getDayCode(endTime));

    }

    private long getStartDay(){
        val calendar = DateUtil.calendar();
        calendar.add(Calendar.DAY_OF_MONTH,-1);
        calendar.set(Calendar.HOUR_OF_DAY,23);
        calendar.set(Calendar.MINUTE,59);
        calendar.set(Calendar.SECOND,59);
        return calendar.getTimeInMillis()/1000;
    }

    private long getEndDay(long daySecond,int day){
        val calendar = DateUtil.calendar(daySecond*1000);
        calendar.add(Calendar.DAY_OF_MONTH,-day);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        return calendar.getTimeInMillis()/1000;
    }

    private int getDayCode(long daySecond){
        val calendar = DateUtil.calendar(daySecond*1000);
        return Integer.parseInt(DateUtil.format(calendar.getTime(), "yyyyMMdd"));
    }
}
